﻿using System.Collections.Generic;
using SWI = System.Windows.Input;
using System;
using System.Linq;
using System.Windows;
using System.Runtime.InteropServices;

namespace Microsoft.Xna.Framework.Input
{
    /// <summary>
    /// Represents a state of keystrokes recorded by a keyboard input device.
    /// </summary>
	[StructLayout(LayoutKind.Sequential)]
    public struct KeyboardState
    {
        #region Fields
		internal Keys[] pressedKeys;

        static Dictionary<Keys, SWI.Key> keyXref;
        static Dictionary<int, Keys> mPlatformSpecificKeys;
        #endregion Private Fields

		#region Properties
		/// <summary>
		/// Returns the state of a particular key.
		/// </summary>
		/// <param name="key">Enumerated value representing the key to query.</param>
		public KeyState this[Keys key]
		{
			get { return pressedKeys.Contains(key) ? KeyState.Down : KeyState.Up; }
		}
		#endregion

		#region Constructor
		/// <summary>
		/// Initializes a new instance of the KeyboardState class.
		/// </summary>
		/// <param name="keys">Array or parameter list of Keys to initialize as pressed.</param>
		public KeyboardState(params Keys[] keys)
		{
			pressedKeys = keys;
		}
		#endregion

		#region Public Methods
		/// <summary>
		/// Returns a value that indicates whether the current instance is equal to a specified object.
		/// </summary>
		/// <param name="obj">Object to compare this object to.</param>
		/// <returns>true if this instance is equal to the specified object; otherwise, false.</returns>
		public override bool Equals(object obj)
		{
			if (obj is KeyboardState)
				return this == (KeyboardState)obj;
			return false;
		}

		/// <summary>
		/// Gets the hash code for this instance.
		/// </summary>
		public override int GetHashCode()
		{
			return pressedKeys.GetHashCode();
		}

		/// <summary>
		/// Returns whether a specified key is currently being pressed.
		/// </summary>
		/// <param name="key">Enumerated value that specifies the key to query.</param>
		public bool IsKeyDown(Keys key)
		{
			return pressedKeys.Contains(key);
		}

		/// <summary>
		/// Returns whether a specified key is currently not pressed.
		/// </summary>
		/// <param name="key">Enumerated value that specifies the key to query.</param>
		public bool IsKeyUp(Keys key)
		{
			return !pressedKeys.Contains(key);
		}

		/// <summary>
		/// Gets an array of values that correspond to the keyboard keys that are currently being pressed.
		/// </summary>
		public Keys[] GetPressedKeys()
		{
			return pressedKeys;
		}
		#endregion

		#region Operators
		/// <summary>
		/// Compares two objects to determine whether they are the same.
		/// </summary>
		/// <param name="a">Object to the left of the equality operator.</param>
		/// <param name="b">Object to the right of the equality operator.</param>
		/// <returns>true if both objects are equal; otherwise, false.</returns>
		public static bool operator ==(KeyboardState a, KeyboardState b)
		{
			return a.pressedKeys.SequenceEqual(b.pressedKeys, new KeysComparer());
		}

		/// <summary>
		/// Compares two objects to determine whether they are different.
		/// </summary>
		/// <param name="a">Object to the left of the inequality operator.</param>
		/// <param name="b">Object to the right of the inequality operator.</param>
		/// <returns>true if the objects are different; otherwise, false.</returns>
		public static bool operator !=(KeyboardState a, KeyboardState b)
		{
			return !a.pressedKeys.SequenceEqual(b.pressedKeys, new KeysComparer());
		}
		#endregion

		private class KeysComparer : IEqualityComparer<Keys>
		{
			public bool Equals(Keys x, Keys y)
			{
				return x == y;
			}

			public int GetHashCode(Keys obj)
			{
				return obj.GetHashCode();
			}
		}
    }
}